package compile;

import common.FileUtil;

import java.io.File;

/**
 * @author vivi
 * @description
 * @date 2024/5/8
 */
//每次的 编译+运行 就成为一个Task
// 参数: 要编译运行的 java 源代码.
// 返回值: 表示编译运行的结果. 编译出错/运行出错/运行正确.....
public class Task {

//    // 通过一组常量来约定临时文件的名字.
//    // 之前这里的名字都是静态常量. 但是现在要实现针对每个请求都有不同的临时目录, 就不能使用静态常量了
//    // 这个表示所有临时文件所在的目录
//    private String WORK_DIR = null;
//    // 约定代码的类名
//    private String CLASS = null;
//    // 约定要编译的代码文件名.
//    private String CODE = null;
//    // 约定存放编译错误信息的文件名
//    private String COMPILE_ERROR = null;
//    // 约定存放运行时的标准输出的文件名
//    private String STDOUT = null;
//    // 约定存放运行时的标准错误的文件名
//    private String STDERR = null;

    //通过一组常量来约定临时文件的名字
    private static final String WORK_DIR = "./tmp/";
    //约定代码的类名
    private static final String CLASS = "Solution";
    //约定要编译的代码文件名
    private static final String CODE = WORK_DIR + "Solution.java";
    //约定存放编译错误信息的文件名
    private static final String COMPILE_ERROR = WORK_DIR + "compileError.txt";
    //约定存放运行时的标准输出的文件名
    private static final String STDOUT = WORK_DIR + "stdout.txt";
    //约定存放运行时的标准错误的文件名
    private static final String STDERR = WORK_DIR + "stderr.txt";

    public Answer compileAndRun(Question question) {
        Answer answer = new Answer();
        //0 先准备好用来存放临时文件的目录
        File workDir = new File(WORK_DIR);
        if(!workDir.exists()){
            //创建多级目录
            workDir.mkdirs();
        }
        //1 把question中的code写入到一个Solution.java文件里面
        FileUtil.writeFile(CODE, question.getCode());
        //2 创建子进程, 调用 javac 进行编译
        String compileCmd = String.format("javac -encoding utf8 %s -d %s", CODE, WORK_DIR);
        CommandUtil.run(compileCmd, null, COMPILE_ERROR);
        // 如果编译出错了, 错误信息就被记录到 COMPILE_ERROR 这个文件中了. 如果没有编译出错, 这个文件是空文件.
        String compileError = FileUtil.readFile(COMPILE_ERROR);
        if(!compileError.equals("")){
            //编译出错
            // 直接返回 compile.compile.Answer, 让 compile.compile.Answer 里面记录编译的错误信息.
            System.out.println("编译出错!");
            answer.setError(1);
            answer.setReason(compileError);
            return answer;
        }
        //编译正确 进入 3
        //3 创建子进程, 调用java命令并执行
        String runCmd = String.format("java -classpath %s %s", WORK_DIR, CLASS);
        System.out.println("运行命令: " + runCmd);
        CommandUtil.run(runCmd, STDOUT, STDERR);
        String runError = FileUtil.readFile(STDERR);
        if (!runError.equals("")) {
            System.out.println("运行出错!");
            answer.setError(2);
            answer.setReason(runError);
            return answer;
        }
        //4 让父进程获取到编译运行的结果，并打包成Answer对象
        answer.setError(0);
        answer.setStdout(FileUtil.readFile(STDOUT));
        return answer;
    }

    public static void main (String[] args) {
        Task task = new Task();
        Question question = new Question();
        question.setCode("public class Solution {\n" +
                "    public static void main (String[] args) {\n" +
                "        System.out.println(\"谢菲 大美女~~\");\n" +
                "    }\n" +
                "}");
        Answer answer = task.compileAndRun(question);
        System.out.println(answer);
    }
}
